package com.ken.callblock2.tools;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.List;
import org.apache.http.util.ByteArrayBuffer;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.support.v4.app.ShareCompat;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class Utils {
	private static String TAG = Utils.class.getSimpleName();
	//
	private Context mContext;

	ConnectivityManager mConnectivityManager;
	TelephonyManager 	mTelephonyMgr;
	
	//----------------------------------------------------------------------------------------------------------------------//
	public final static long SIZE_KB = 1024L;
	public final static long SIZE_MB = SIZE_KB * SIZE_KB;
	public final static long SIZE_GB = SIZE_KB * SIZE_KB * SIZE_KB;
	//return Number of bytes available on external storage
	public static long getExternalAvailableSpaceInBytes() {
        long availableSpace = -1L;
        try {
            StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
            availableSpace = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
        } catch (Exception e) {	e.printStackTrace(); }
        return availableSpace;
    }	
	// return Number of kilo bytes available on external storage
	public static long getExternalAvailableSpaceInKB(){	return getExternalAvailableSpaceInBytes()/SIZE_KB;	}
	// return Number of Mega bytes available on external storage
	public static long getExternalAvailableSpaceInMB(){	return getExternalAvailableSpaceInBytes()/SIZE_MB;	}
	// return gega bytes of bytes available on external storage
	public static long getExternalAvailableSpaceInGB(){	return getExternalAvailableSpaceInBytes()/SIZE_GB;	}
	// return Total number of available blocks on external storage
	public static long getExternalStorageAvailableBlocks() {
        long availableBlocks = -1L;
        try {
            StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
            availableBlocks = stat.getAvailableBlocks();
        } catch (Exception e) { e.printStackTrace(); }
        return availableBlocks;
    }
	//----------------------------------------------------------------------------------------------------------------------//
	// 用來記錄可能會被更新的網路連線狀態...
	public class NetworkState {
	    public 	String 	mTypeName 		= "Unknown";
	    public 	String 	mSubtypeName 	= "Unknown";
	    public 	boolean mAvailable 		= false;
	}
	public NetworkState mNetworkState = new NetworkState();
	
	//----------------------------------------------------------------------------------------------------------------------//
	public Utils(Context context) {
		// TODO Auto-generated constructor stub
		mContext	= context;
		mConnectivityManager 	= (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
		mTelephonyMgr 			= (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
	}
	//----------------------------------------------------------------------------------------------------------------------//
	public boolean isNetworkAvailable() {
		boolean isAvailable = false;
		if(mConnectivityManager != null) {
			NetworkInfo[] info = mConnectivityManager.getAllNetworkInfo();
			if(info != null) {
				for(int i = 0; i < info.length; i++) {
					if(info[i].getState() == NetworkInfo.State.CONNECTED) {
						isAvailable = true;
						break;
					}
				}
			}
		}
		return isAvailable;
	}
	// 
	public int getSdkVersion(){
		return Build.VERSION.SDK_INT;
	}
	
	/**
	 * This method tells you how many total bytes of heap your app is allowed to use.
	 * @return
	 */
	public long getMaxMemory(){
		Runtime rt = Runtime.getRuntime();
		return rt.maxMemory();
	}
	
	/**
	 * This method tells you approximately how many megabytes of heap your app should 
	 * use if it wants to be properly respectful of the limits of the present device.
	 * @param activity
	 * @return
	 */
	public int getMemorySuggestion(Context context){
		ActivityManager am = (ActivityManager) context.getSystemService(Activity.ACTIVITY_SERVICE);	
		return am.getMemoryClass();
	}
	
	public int getOrientation(){
		int ot = mContext.getResources().getConfiguration().orientation;
		return ot;
	}

	public String getIMSI(){
		String imsi = mTelephonyMgr.getSubscriberId();
		return imsi;
	}

	public String getIMEI(){
		String imei = mTelephonyMgr.getDeviceId();
		return imei;
	}
	
	public boolean isTablet(){
		if (hasGingerbread()){
		    boolean xlarge 	= ((mContext.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE);
		    boolean large 	= ((mContext.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE);
		    return (xlarge || large);
		}else{
			boolean large 	= ((mContext.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE);
			return large;
		}
	}
	
	public boolean isXLarge(){
		if (hasGingerbread()){
		    boolean xlarge 	= ((mContext.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE);		    
		    return xlarge;
		}else
			return false;
	}
	
	// 取得裝置唯一性編號 用來提供給Feed使用...用各種方式組合而成...
	public String getUniqueID(){
		TelephonyManager tpm 	= (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
		String m_szImei 		= "QAZWSXEDCRFV";
		if (null != tpm)
			m_szImei = tpm.getDeviceId(); // Requires READ_PHONE_STATE

		String m_szDevIDShort = "35" + //we make this look like a valid IMEI
				Build.BOARD.length()%10+ Build.BRAND.length()%10 +
				Build.CPU_ABI.length()%10 + Build.DEVICE.length()%10 +
				Build.DISPLAY.length()%10 + Build.HOST.length()%10 +
				Build.ID.length()%10 + Build.MANUFACTURER.length()%10 +
				Build.MODEL.length()%10 + Build.PRODUCT.length()%10 +
				Build.TAGS.length()%10 + Build.TYPE.length()%10 +
				Build.USER.length()%10 ; //13 digits

		WifiManager wm 		= (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
		String m_szWLANMAC 	= "QWEASDZXCRTY";
		if (null != wm)
			m_szWLANMAC = wm.getConnectionInfo().getMacAddress();

		BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
		String m_szBTMAC 	= "QSCZDRTGNBFU";
		if (null != bt)
			m_szBTMAC = bt.getAddress();
		
		String m_szLongID = m_szImei + m_szDevIDShort + m_szWLANMAC + m_szBTMAC;
		
		// create a hex string
		String m_szUniqueID = new String();
		// compute md5
		MessageDigest md5 = null;
		try {
			md5 = MessageDigest.getInstance("MD5");
			
			md5.update(m_szLongID.getBytes(), 0, m_szLongID.length());
			// get md5 bytes
			byte p_md5Data[] = md5.digest();

			for (int i = 0 ; i < p_md5Data.length ; i++) {
				int b = (0xFF & p_md5Data[i]);
				// if it is a single digit, make sure it have 0 in front (proper padding)
				if (b <= 0xF) m_szUniqueID += "0";
				// add number to string
				m_szUniqueID += Integer.toHexString(b);
			}
			// hex string to uppercase
			m_szUniqueID = m_szUniqueID.toUpperCase();	
			m_szUniqueID = "A" + m_szUniqueID;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		//
		return m_szUniqueID;
	}
	
	//----------------------------------------------------------------------------------------------------------------------//
	// translate dip to pixel unit...
	public int dip2px(float dpValue) {

		final float scale = mContext.getResources().getDisplayMetrics().density;  
		return (int) (dpValue * scale + 0.5f);  
	}  
	// translate pixel to dip unit...
	public int px2dip(float pxValue) {  

		final float scale = mContext.getResources().getDisplayMetrics().density;  
		return (int) (pxValue / scale + 0.5f);  
	}
	// translate pixel to sp unit...
	public int px2sp(float pxValue){
		float scaledDensity = mContext.getResources().getDisplayMetrics().scaledDensity; 
	    return (int)(pxValue/scaledDensity); 
	}
	// translate sp unit to pixel...
	public int sp2px(float spValue){
		float scaledDensity = mContext.getResources().getDisplayMetrics().scaledDensity; 
	    return (int)(spValue*scaledDensity); 
	}	
	//
	public int getScreenWidth(){

		final int width = mContext.getResources().getDisplayMetrics().widthPixels;
		return width;
	}
	//
	public int getScreenHeight(){

		final int height = mContext.getResources().getDisplayMetrics().heightPixels;
		return height;
	}

	public static int getRandom(int start, int end) {
		return (int) (Math.random() * (end - start + 1)) + start;
	}
	//
	public boolean DownloadFromUrl(String DownloadUrl, String path, String fileName) {
		//
		try {
			URL url = new URL(DownloadUrl); //you can write here any link
//			File menudir = new File(((SHEKland)mContext).getCachePath(), "menu");
//			if (false == menudir.exists()){
//				menudir.mkdirs();
//			}
			String tmpName = fileName + "_tmp";
			File file = new File(path, tmpName);

			long startTime = System.currentTimeMillis();
			KENLog.d(TAG, "download begining");
			KENLog.d(TAG, "download url:" + url);
			KENLog.d(TAG, "downloaded file name:" + fileName);

			/* Open a connection to that URL. */
			URLConnection ucon = url.openConnection();
			ucon.setReadTimeout(30000);
			/*
			 * Define InputStreams to read from the URLConnection.
			 */
			InputStream is = ucon.getInputStream();
			BufferedInputStream bis = new BufferedInputStream(is);

			/*
			 * Read bytes to the Buffer until there is nothing more to read(-1).
			 */
			ByteArrayBuffer baf = new ByteArrayBuffer(5000);
			int current = 0;
			while ((current = bis.read()) != -1) {
				baf.append((byte) current);
			}


			/* Convert the Bytes read to a String. */
			FileOutputStream fos = new FileOutputStream(file);
			fos.write(baf.toByteArray());
			fos.flush();
			fos.close();
			KENLog.d(TAG, "download ready in" + ((System.currentTimeMillis() - startTime) / 1000) + " sec");
			// 下載成功以後才會把暫存檔名換成真正的檔名...
			file.renameTo(new File(path, fileName));

		} catch (IOException e) {
			KENLog.d(TAG, "Error: " + e);
			return false;
		}
		return true;
	}
	//
	public Bitmap getBitmapFromResource(int resId, int reqWidth, int reqHeight) {
		BitmapFactory.Options opt = new BitmapFactory.Options();
		opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
		opt.inPurgeable 		= true;
		opt.inInputShareable 	= true;
		opt.inJustDecodeBounds 	= true;
		try {
			BitmapFactory.Options.class.getField("inNativeAlloc").setBoolean(opt,true);
		} catch (IllegalArgumentException e1) {
			e1.printStackTrace();
		} catch (SecurityException e1) {
			e1.printStackTrace();
		} catch (IllegalAccessException e1) {
			e1.printStackTrace();
		} catch (NoSuchFieldException e1) {
			e1.printStackTrace();
		}

		InputStream is = mContext.getResources().openRawResource(resId);
		BitmapFactory.decodeStream(is, null, opt);
		opt.inJustDecodeBounds = false; 
		int scale = 1;
		scale = calculateInSampleSize(opt, reqWidth, reqHeight);
		opt.inSampleSize = scale;
		return BitmapFactory.decodeStream(is, null, opt);
	}
	//
	public Bitmap getBitmapFromFile(File f, int reqWidth, int reqHeight){
	    Bitmap b = null;
	    // First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options o = new BitmapFactory.Options();
		o.inJustDecodeBounds = true;

		FileInputStream fis;
		try {
			fis = new FileInputStream(f);
			BitmapFactory.decodeStream(fis, null, o);
			fis.close();
			o.inJustDecodeBounds = false;
			//
			int scale = 1;
			// Calculate inSampleSize
			scale = calculateInSampleSize(o, reqWidth, reqHeight);
			//Decode with inSampleSize
			//BitmapFactory.Options o2 = new BitmapFactory.Options();
			o.inSampleSize 			= scale;
			o.inPreferredConfig 	= Bitmap.Config.ARGB_8888;
			o.inPurgeable 			= true;
			o.inInputShareable 		= true;        
			fis = new FileInputStream(f);
			b = BitmapFactory.decodeStream(fis, null, o);
			fis.close();
			//b = BitmapFactory.decodeFile(f.getAbsolutePath(), o);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//BitmapFactory.decodeFile(f.getAbsolutePath(), o);

	    return b;
	}
	// 計算合理的取樣大小...
	public static int calculateInSampleSize(
			BitmapFactory.Options options, int reqWidth, int reqHeight) {
		// Raw height and width of image
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {

			// Calculate ratios of height and width to requested height and width
			final int heightRatio = Math.round((float) height / (float) reqHeight);
			final int widthRatio = Math.round((float) width / (float) reqWidth);

			// Choose the smallest ratio as inSampleSize value, this will guarantee
			// a final image with both dimensions larger than or equal to the
			// requested height and width.
			inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
		}

		return inSampleSize;
	}	
	// read json string from json file in /raw resource folder...
	public String JSONGetStringfromRAW(int rawid){
		InputStream is = mContext.getResources().openRawResource(rawid); 
		Writer writer = new StringWriter(); 
		char[] buffer = new char[1024]; 
		try { 
		    Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 
		    int n; 
		    while ((n = reader.read(buffer)) != -1) { 
		        writer.write(buffer, 0, n); 
		    } 
		} catch (UnsupportedEncodingException e){
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally { 
		    if (is != null)
				try {
					is.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} 
		} 
		 
		String jsonString = writer.toString(); 
		return jsonString;
	}
	//
	public BufferedReader JSONGetReaderfromRAW(int rawid){
		InputStream is = mContext.getResources().openRawResource(rawid); 
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return reader;
	}
	// 
	public static void writeLog(String FolderName, String fileName, String data) {
		Writer writer;
		File root = Environment.getExternalStorageDirectory();
		File outDir = new File(root.getAbsolutePath() + File.separator + FolderName);
		if (!outDir.isDirectory()) {
			outDir.mkdir();
		}
		try {
			if (!outDir.isDirectory()) {
				throw new IOException("Unable to create directory EZ_time_tracker. Maybe the SD card is mounted?");
			}
			File outputFile = new File(outDir, fileName);
			writer = new BufferedWriter(new FileWriter(outputFile));
			writer.write(data);
			//Toast.makeText(mContext, "Report successfully saved to: " + outputFile.getAbsolutePath(), Toast.LENGTH_LONG).show();
			writer.close();
		} catch (IOException e) {
			//Toast.makeText(mContext, e.getMessage() + " Unable to write to external storage.", Toast.LENGTH_LONG).show();
		}
	}	

	public void sendSMS(Activity a, String message){
		Intent sendIntent = new Intent(Intent.ACTION_VIEW);
		sendIntent.putExtra("sms_body", message); 
		sendIntent.setType("vnd.android-dir/mms-sms");
		sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		a.startActivity(sendIntent);
	}

	public void enumEmailAccount(List<String> Emails){
		if (Emails == null) return;

		Emails.clear();
		Account[] accounts = AccountManager.get(mContext).getAccounts();
		for (Account account : accounts) {
			Iterator<String> it = Emails.iterator();
			boolean find = false;
			while(it.hasNext()){
				if (it.next().equals(account.name)){
					find = true;
					break;
				}
			}
			if (find==false && account.name.contains("@")){ // remove duplication and illegal address...
				Emails.add(account.name);
				//Log.d("enumEmailAccount", "Email = " + account.name);
			}    		
		}
	}

	public void sendEmail(Activity a, String subject, String content, String ChooserTitle){

		// these fields will not be used...just memo...
		//    	String aEmailList[] = { "user@fakehost.com","user2@fakehost.com" };  
		//    	String aEmailCCList[] = { "user3@fakehost.com","user4@fakehost.com"};  
		//    	String aEmailBCCList[] = { "user5@fakehost.com" };      	  
		//    	emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, aEmailList);  
		//    	emailIntent.putExtra(android.content.Intent.EXTRA_CC, aEmailCCList);  
		//    	emailIntent.putExtra(android.content.Intent.EXTRA_BCC, aEmailBCCList);
		//    	emailIntent.setType("application/octet-stream");
		//    	emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));  // Attachment...
		//    	emailIntent.setType("text/html");
		//    	emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, Html.fromHtml("<b>this is html text in email body.</b>"));

		Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);

		emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
		emailIntent.setType("plain/text");
		emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, content);
		emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		a.startActivity(Intent.createChooser(emailIntent, ChooserTitle));

	}

	public void postTextOnGoolePlus(Activity a, String message){ // post text message on Google+ wall...

		Intent shareIntent = ShareCompat.IntentBuilder.from(a)
				.setText(message)
				.setType("text/plain")
				.getIntent()
				.setPackage("com.google.android.apps.plus")
				.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

		a.startActivity(shareIntent);
	}

	public void postMediaOnGooglePlus(Activity a, String message, Uri MEDIA_URI, String MEDIA_TYPE){ // post media(like image/png or video/mp4...) on Google+ wall...
		Intent shareIntent = ShareCompat.IntentBuilder.from(a)
				.setText(message)
				.setStream(MEDIA_URI)
				.setType(MEDIA_TYPE)
				.getIntent()
				.setPackage("com.google.android.apps.plus")
				.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

		a.startActivity(shareIntent);
	}
	
	public void sendTweet(Activity a, String message){ // post text message on Twitter wall...
		
        String tweetUrl = "https://twitter.com/intent/tweet?text=" + message;
        Uri uri = Uri.parse(tweetUrl);
        a.startActivity(new Intent(Intent.ACTION_VIEW, uri).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
	}
	
	/**
	 * 用於給參數inSimpleSize用
	 * @param bm
	 * @return
	 */
	public java.io.InputStream Bitmap2InputStream(Bitmap bm){  
    	ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    	bm.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos); 
    	byte[] bitmapdata = bos.toByteArray();
    	   
        ByteArrayInputStream bs = new ByteArrayInputStream(bitmapdata);  
        return bs;
    } 
	
	//------------------------------------------------------------------------------------------//
	
    public static boolean hasFroyo() {
        // Can use static final constants like FROYO, declared in later versions
        // of the OS since they are inlined at compile time. This is guaranteed behavior.
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
    }

    public static boolean hasGingerbread() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
    }

    public static boolean hasHoneycomb() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
    }

    public static boolean hasHoneycombMR1() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1;
    }

    public static boolean hasJellyBean() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
    }	
}
